﻿using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Singer.Shared;
using Singer.Shared.Modularity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace Singer.Middleware.JwtAuth
{
    /// <summary>
    /// 验证token是否有效
    /// 从每次请求携带的JwtToken中解析出登录的用户信息 
    /// </summary>
    public class JwtAuthCheckFilter : IAsyncActionFilter
    {
        public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
        {
            string token = ReadToken(context).Token;
            var endpoint = context.HttpContext.Features.Get<IEndpointFeature>()?.Endpoint;
            if (endpoint == null || endpoint.Metadata.Count() == 0)
            {
                await next();
                return;
            }
            var allowAnonymousAttribute = endpoint.Metadata.Any(x => x is AllowAnonymousAttribute);
            if (allowAnonymousAttribute)
            {
                await next();
                return;
            }
            List<AuthorizeAttribute>? authorizes = endpoint?.Metadata.Where(x => x is AuthorizeAttribute).Select(x => (AuthorizeAttribute)x).ToList();
            var jwtAuth = authorizes?.FirstOrDefault(x => x != null && x.AuthenticationSchemes == JwtBearerDefaults.AuthenticationScheme);
            if (jwtAuth == null)
            {
                await next();
                return;
            }
            IJwtAuthTokenManager? tokenManager = context.HttpContext.RequestServices.GetService<IJwtAuthTokenManager>();
            if (tokenManager != null)
            {
                if (string.IsNullOrWhiteSpace(token))
                    throw new CoreException("身份认证失效", ErrorCode.Auth);
                //判断缓存中是否存在
                bool existsToken = await tokenManager.ExistsTokenAsync(token);
                if (!existsToken)
                    throw new CoreException("身份认证失效", ErrorCode.Auth);
            }
            await next();
        }

        /// <summary>
        /// 解析JwtToken中的用户信息，放入用户信息上下文中
        /// </summary>
        private IUserContext ReadToken(ActionExecutingContext context)
        {
            DefaultUserContext userContext = new DefaultUserContext()
            {
                Ip = context.HttpContext.Connection.RemoteIpAddress?.MapToIPv4()?.ToString() ?? ""
            };
            //解析请求中携带的JwtToken
            string? bearerToken = context.HttpContext.Request.Headers["Authorization"].FirstOrDefault();
            if (!string.IsNullOrWhiteSpace(bearerToken) && bearerToken.StartsWith(JwtBearerDefaults.AuthenticationScheme + " "))
            {
                string token = bearerToken.Split(' ')[1];
                ClaimsPrincipal? user = JwtAuthTokenManager.ReadToken(token);
                if (user != null)
                {
                    context.HttpContext.User = user;
                    userContext.UserId = user?.Claims?.Where(x => x.Type == nameof(IUserContext.UserId)).FirstOrDefault()?.Value ?? "";
                    userContext.UserName = user?.Claims?.Where(x => x.Type == nameof(IUserContext.UserName)).FirstOrDefault()?.Value ?? "";
                    userContext.Mobile = user?.Claims?.Where(x => x.Type == nameof(IUserContext.Mobile)).FirstOrDefault()?.Value ?? "";
                    userContext.Token = token;
                };
            }
            IUserContextAccessor? userContextAccessor = context.HttpContext.RequestServices.GetService<IUserContextAccessor>();
            if (userContextAccessor != null)
                userContextAccessor.UserContext = userContext;
            return userContext;
        }
    }
}
